﻿//----------------------------------------------------------------------------------------------------
// The The Level Editor State of the game
//----------------------------------------------------------------------------------------------------

package HG.GameStates
{
	import flash.events.*;
	import flash.geom.Point;
	
	import HG.Debug;
	import HG.GameService;
	import HG.Managers.StateManager;
	import HG.Managers.NodeManager;
	import HG.Managers.LevelManager;
	
	import HG.Visual.VisualNode;
	import HG.Visual.VisualConnection;
	
	import HG.Events.LevelEvent;
	import HG.Managers.GameRuleManager;
	import HG.Managers.CameraManager;

	public class EditorState extends IGameState
	{
		var m_stateManager:StateManager;
		var m_nodeManager:NodeManager;
		var m_levelManager:LevelManager;
		var m_gameRuleManager:GameRuleManager;
		var m_cameraManager:CameraManager;
		
		var m_optionsOpen:Boolean;
		var m_toolboxOpen:Boolean;
		
		var m_mouseDrag:Boolean;
		
		var m_draggingObj:Object;
		var m_originalSource:Number;
		
		//----------------------------------------------------------------------------------------------------
		public function EditorState()
		{
			m_stateName = "EditorState";
		}
		
		//----------------------------------------------------------------------------------------------------
		public override function Begin()
		{
			super.Begin();
			
			m_stateManager = GameService.GetInstance().GetStateManager();
			m_nodeManager = GameService.GetInstance().GetNodeManager();
			m_levelManager = GameService.GetInstance().GetLevelManager();
			m_gameRuleManager = GameService.GetInstance().GetGameRuleManager();
			m_cameraManager = GameService.GetInstance().GetCameraManager();
			
			Debug.ASSERT(m_movie, "No Editor Clip");
			Debug.ASSERT(m_movie.Content, "No Editor Content");
			
			// Editor modes
			m_gameRuleManager.SetEditorMode(true);
			m_levelManager.SetEditorMode(true);
			m_movie.Content.LevelCanvas.LevelHolder.SetEditorMode(true);
			
			// Options menu
			m_movie.Content.Options.Button_Gear.addEventListener(MouseEvent.CLICK, Button_Gear);
			m_movie.Content.Options.Content.Button_Back.addEventListener(MouseEvent.CLICK, Button_Back);
			m_movie.Content.Options.Content.Button_New.addEventListener(MouseEvent.CLICK, Button_New);
			m_movie.Content.Options.Content.Button_Save.addEventListener(MouseEvent.CLICK, Button_Save);
			m_movie.Content.Options.Content.Button_Open.addEventListener(MouseEvent.CLICK, Button_Open);
			m_movie.Content.Options.Content.Button_Share.addEventListener(MouseEvent.CLICK, Button_Share);
			m_movie.Content.Options.Content.Button_Configure.addEventListener(MouseEvent.CLICK, Button_Configure);
			
			// Toolbox Menu
			m_movie.Content.Toolbox.Button_Box.addEventListener(MouseEvent.CLICK, Button_Box);
			m_movie.Content.Toolbox.Content.Button_Connection.addEventListener(MouseEvent.MOUSE_DOWN, Button_Connection);
			
			//Ensure options menu is closed
			m_optionsOpen = false;
			m_movie.Content.Options.gotoAndStop('hide');
			
			//Ensure toolbox menu is closed
			m_toolboxOpen = false;
			m_movie.Content.Toolbox.Button_Box.visible = false;
			m_movie.Content.Toolbox.Button_Trash.visible = false;
			m_movie.Content.Toolbox.gotoAndStop('hide');
			
			// Hide the levelHolder
			m_movie.Content.LevelCanvas.LevelHolder.visible = false;
			
			m_cameraManager.SetCanvas(m_movie.Content.LevelCanvas);
			
			
			// Populate the Node List
			m_movie.Content.Toolbox.Content.NodeList.Populate(m_nodeManager.GetNodeTypes());
			m_movie.Content.Toolbox.Content.NodeList.AttachAddNodeListener(OnToolboxNewNode);
			
			m_levelManager.SetVisualLevelContainer(m_movie.Content.LevelCanvas.LevelHolder);
			m_levelManager.addEventListener(LevelEvent.LOAD, OnLevelLoaded);
		}
		
		//----------------------------------------------------------------------------------------------------
		public override function End()
		{
			super.End();
		}
		
		//----------------------------------------------------------------------------------------------------
		public override function OnTick(DetaTime:Number)
		{
			if (!m_mouseDrag)
				return;
				
			var mousePos:Point = new Point(m_movie.mouseX, m_movie.mouseY);
			mousePos = m_movie.localToGlobal(mousePos);
			
			var points:Array ;
			
			if(m_draggingObj.GetType() == "Connection")
			{
				points = m_movie.Content.LevelCanvas.LevelHolder.GetNearestConnectionPoints(mousePos, true);
				
				if (!points)
					return;
				
				m_draggingObj.SetSource(points[0], true);
				m_draggingObj.SetTarget(points[1], true);
			}
			else
			{
				points = m_movie.Content.LevelCanvas.LevelHolder.GetNearestConnectionPoints(mousePos, false);
				
				if (!points)
					return;
					
				m_draggingObj.SetSource(points[0], true);
			}
		
			
			// trash
			if(m_movie.Content.Toolbox.Button_Trash.hitTestPoint(mousePos.x, mousePos.y))
			{
				m_movie.Content.Toolbox.Button_Trash.gotoAndStop('open');
			}
			else
			{
				m_movie.Content.Toolbox.Button_Trash.gotoAndStop('closed');
			}
			
		}
		
		//----------------------------------------------------------------------------------------------------
		public function OnLevelLoaded(evt:LevelEvent)
		{
			m_movie.Content.Toolbox.Button_Box.visible = true;
			
			var nodes:Array = m_movie.Content.LevelCanvas.LevelHolder.GetVisualNodes();
			
			var index:Number = 0;
			var listLength:Number = nodes.length;
			
			for (index = 0; index < listLength; ++index)
			{
				nodes[index].addEventListener(MouseEvent.MOUSE_DOWN, OnNodePressed);
				nodes[index].addEventListener(MouseEvent.MOUSE_UP, OnNodeReleased);
				
				nodes[index].SetVisible(true);
			}
			
			m_movie.addEventListener(MouseEvent.MOUSE_UP, OnNodeReleased);
			
			
			var connections:Array = m_movie.Content.LevelCanvas.LevelHolder.GetVisualConnections();
			
			index = 0;
			listLength = connections.length;
			
			for (index = 0; index < listLength; ++index)
			{
				AddConnectionCalls(connections[index]);
				connections[index].SetVisible(true);
			}
		}
		
		//----------------------------------------------------------------------------------------------------
		private function AddConnectionCalls(visCon:VisualConnection)
		{
			visCon.Line.Content.Area.addEventListener(MouseEvent.MOUSE_DOWN, OnConnectionPressed);
			visCon.Line.Content.Area.addEventListener(MouseEvent.MOUSE_UP, OnNodeReleased);
		
			visCon.Line.Content.Area.visible = true;
			visCon.Line.Content.DirBtn.visible = true;
			visCon.Line.Content.DirBtn.con = visCon;
			visCon.Line.Content.DirBtn.addEventListener(MouseEvent.MOUSE_UP, OnDirChange);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function ShowOptionsMenu(show:Boolean)
		{
			if (show == m_optionsOpen)
				return;
			
			if (show)
			{
				m_optionsOpen = true;
				m_movie.Content.Options.gotoAndPlay('in');
			}
			else
			{
				m_optionsOpen = false;
				m_movie.Content.Options.gotoAndPlay('out');
			}
		}
		
		//----------------------------------------------------------------------------------------------------
		private function openNodeEditor(visNode:VisualNode)
		{
			m_movie.Content.NodeEditor.SetNode(visNode);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function OpenLevelConfigurator()
		{
			m_movie.Content.LevelConfig.Open(m_movie.Content.LevelCanvas.LevelHolder);
		}
		
		//----------------------------------------------------------------------------------------------------
		// Button Callbacks
		//----------------------------------------------------------------------------------------------------
		private function Button_Back(me:MouseEvent)
		{
			m_stateManager.SwitchtoState(StateManager.STATE_MENU);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function Button_Gear(me:MouseEvent)
		{
			if (!m_optionsOpen)
			{
				ShowOptionsMenu(true);
			}
			else
			{
				ShowOptionsMenu(false);
			}
		}
		
		//----------------------------------------------------------------------------------------------------
		private function Button_New(me:MouseEvent)
		{
			//m_stateManager.SwitchtoState(StateManager.STATE_MENU);
			m_levelManager.CreateLevel();
			
			m_movie.Content.LevelCanvas.LevelHolder.ClearAll();
			m_movie.Content.LevelCanvas.LevelHolder.visible = true;
			
			OpenLevelConfigurator();
			
			ShowOptionsMenu(false);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function Button_Save(me:MouseEvent)
		{
			//m_stateManager.SwitchtoState(StateManager.STATE_MENU);
			ShowOptionsMenu(false);
			
			m_levelManager.SetLevelDataFromVisual();
			
			m_levelManager.SaveCurrentLevel();
		}
		
		//----------------------------------------------------------------------------------------------------
		private function Button_Open(me:MouseEvent)
		{
			m_levelManager.LoadLevel(0);
			m_movie.Content.LevelCanvas.LevelHolder.ClearAll();
			ShowOptionsMenu(false);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function Button_Share(me:MouseEvent)
		{
			//m_stateManager.SwitchtoState(StateManager.STATE_MENU);
			ShowOptionsMenu(false);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function Button_Configure(me:MouseEvent)
		{
			OpenLevelConfigurator();
			ShowOptionsMenu(false);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function Button_Box(me:MouseEvent)
		{
			if (!m_toolboxOpen)
			{
				m_toolboxOpen = true;
				m_movie.Content.Toolbox.gotoAndPlay('in');
			}
			else
			{
				m_toolboxOpen = false;
				m_movie.Content.Toolbox.gotoAndPlay('out');
			}
		}
		
		//----------------------------------------------------------------------------------------------------
		private function Button_Connection(me:MouseEvent):void
		{
			var newConnection:VisualConnection = m_movie.Content.LevelCanvas.LevelHolder.AddVisualConnection();
			
			DragObj(newConnection);
			
			AddConnectionCalls(newConnection);
			
			newConnection.SetVisible(true);
		}
		//----------------------------------------------------------------------------------------------------
		
		//----------------------------------------------------------------------------------------------------
		// Editor
		//----------------------------------------------------------------------------------------------------
		private function OnToolboxNewNode(type:String)
		{
			var newNode:VisualNode = m_movie.Content.LevelCanvas.LevelHolder.AddVisualNode(type, -1);

			DragObj(newNode);
			
			newNode.addEventListener(MouseEvent.MOUSE_DOWN, OnNodePressed);
			newNode.addEventListener(MouseEvent.MOUSE_UP, OnNodeReleased);
			m_movie.addEventListener(MouseEvent.MOUSE_UP, OnNodeReleased);
			
			newNode.SetVisible(true);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function OnNodePressed(me:MouseEvent)
		{
			DragObj(VisualNode(me.currentTarget));
		}
		
		//----------------------------------------------------------------------------------------------------
		private function OnConnectionPressed(me:MouseEvent)
		{
			DragObj(VisualConnection(me.currentTarget.parent.parent.parent));
		}
		
		//----------------------------------------------------------------------------------------------------
		private function OnNodeReleased(me:MouseEvent)
		{
			if (!m_mouseDrag)
				return;
				
			DropObj(m_draggingObj);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function OnDirChange(me:MouseEvent)
		{
			var visCon:VisualConnection = me.currentTarget.con;
			
			var fromID:Number = visCon.GetSource().GetVisualNodeID();
			var fromNode:VisualNode = m_levelManager.GetVisualNode(fromID);
			
			var toID:Number = visCon.GetTarget().GetVisualNodeID();
			var toNode:VisualNode = m_levelManager.GetVisualNode(toID);
			
			if (fromNode.GetIsConnectedTo(toID) && 
				toNode.GetIsConnectedTo(fromID))
			{
				// Currently a two-way connection (from <-> to) make fowards only (from -> to)
				toNode.RemoveConnection(fromID);
			}
			else
			
			if (fromNode.GetIsConnectedTo(toID) &&
				!toNode.GetIsConnectedTo(fromID))
			{
				// currently a forwards only connection (from -> to) make backwards only (from <- to)
				toNode.AddConnection(fromID);
				fromNode.RemoveConnection(toID);
			}
			else
			
			if (!fromNode.GetIsConnectedTo(toID) &&
				toNode.GetIsConnectedTo(fromID))
			{
				// currently a backwards only connection (from <- to) make two-way (from <-> to)
				fromNode.AddConnection(toID);
			}
			
			
			visCon.Update();
		}
		
		//----------------------------------------------------------------------------------------------------
		private function DragObj(obj:Object)
		{  
			m_cameraManager.LockCamera(true);
		
			m_mouseDrag = true;
			//obj.startDrag(true);
			m_draggingObj = obj;
			
			m_movie.Content.Toolbox.Button_Box.visible = false;
			m_movie.Content.Toolbox.Button_Trash.visible = true;
			
			//
			if (m_draggingObj.GetType() == "Connection" && m_draggingObj.GetSource())
			{
				var node1:VisualNode = m_movie.Content.LevelCanvas.LevelHolder.GetVisualNode(m_draggingObj.GetSource().GetVisualNodeID());
				var node2:VisualNode = m_movie.Content.LevelCanvas.LevelHolder.GetVisualNode(m_draggingObj.GetTarget().GetVisualNodeID());
				
				node1.RemoveConnection(node2.GetID());
				node2.RemoveConnection(node1.GetID());
			}
			
			if (m_draggingObj.GetSource())
			{
				m_originalSource = m_draggingObj.GetSource().GetID();
			}
			else
			{
				m_originalSource = 0;
			}
			
			m_draggingObj.alpha = 0.5;
			m_draggingObj.ClearSource();
			
			var mousePos:Point = new Point(m_movie.mouseX, m_movie.mouseY);
			mousePos = m_movie.localToGlobal(mousePos);
		}
		
		//----------------------------------------------------------------------------------------------------
		private function DropObj(obj:Object)
		{
			m_cameraManager.LockCamera(false);
			
			m_mouseDrag = false
			//m_draggingObj.stopDrag();
			
			m_movie.Content.Toolbox.Button_Box.visible = true;
			m_movie.Content.Toolbox.Button_Trash.visible = false;
			
			m_draggingObj.alpha = 1;
			//m_shadowObj.visible = false;
			
			var mousePos:Point = new Point(m_movie.mouseX, m_movie.mouseY);
			mousePos = m_movie.localToGlobal(mousePos);
			
			
			// trash
			if(m_movie.Content.Toolbox.Button_Trash.hitTestPoint(mousePos.x, mousePos.y))
			{
				
				if (obj.GetType() != "Connection")
				{
					// When deleting nodes, it is important to remove all connections TO it from other nodes.
					var visNode:VisualNode = VisualNode(obj);
					var visNodeID:Number = visNode.GetID();
					var cons:Array = visNode.GetConnections();
					
					var index:Number = 0;
					var listLength:Number = cons.length;
					
					for (index = 0; index < listLength; ++index)
					{
						var nodeID:Number = cons[index];
						
						var visCon:VisualConnection = m_movie.Content.LevelCanvas.LevelHolder.GetVisualConnection(nodeID, visNodeID);
						m_movie.Content.LevelCanvas.LevelHolder.DeleteVisualObject(visCon);
						
						var conVisNode:VisualNode = m_movie.Content.LevelCanvas.LevelHolder.GetVisualNode(nodeID);
						conVisNode.RemoveConnection(visNodeID);
					}
				}
				
				// Delete this one.
				m_movie.Content.LevelCanvas.LevelHolder.DeleteVisualObject(m_draggingObj);
				m_draggingObj = undefined;
				return;
			}
			
			// Snap the node to the nearest slot
			var points:Array;
			if(m_draggingObj.GetType() == "Connection")
			{
				points = m_movie.Content.LevelCanvas.LevelHolder.GetNearestConnectionPoints(mousePos, true);
				
				if (!points)
				{
					m_movie.Content.LevelCanvas.LevelHolder.DeleteVisualObject(m_draggingObj);
					return;
				}
				
				var node1:VisualNode = m_movie.Content.LevelCanvas.LevelHolder.GetVisualNode(points[0].GetVisualNodeID());
				var node2:VisualNode = m_movie.Content.LevelCanvas.LevelHolder.GetVisualNode(points[1].GetVisualNodeID());
				
				// If these two points are already connected, remove the new connection
				if (node1.GetIsConnectedTo(node2.GetID()) ||
					node2.GetIsConnectedTo(node1.GetID()))
				{
					m_movie.Content.LevelCanvas.LevelHolder.DeleteVisualObject(m_draggingObj);
					return;
				}
				
				node1.AddConnection(node2.GetID());
				node2.AddConnection(node1.GetID());
					
				m_draggingObj.SetSource(points[0], false);
				m_draggingObj.SetTarget(points[1], false);
			}
			else
			{
				points = m_movie.Content.LevelCanvas.LevelHolder.GetNearestConnectionPoints(mousePos, false);
				m_draggingObj.SetSource(points[0], false);
				
				if (m_originalSource == m_draggingObj.GetSource().GetID())
				{
					openNodeEditor(VisualNode(m_draggingObj));
				}
			}
		}
		
		//----------------------------------------------------------------------------------------------------
	}

}











